/**************************************************************************
 * Copyright (C) 2017-2017  Unisound
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 **************************************************************************
 *
 * Description : hb_smart_ac.c
 * Author      : wufangfang@unisound.com
 * Date        : 2020.04.03
 *
 **************************************************************************/
#include "unione.h"
#include "ac_device_simulator.h"
#include "user_asr.h"
#include "user_player.h"

#define TAG "smart_ac"

static char g_power_off_reply[32] = {0};
static int _ac_power_replay(event_custom_setting_t *setting) {
  eAcSate state = eACSTATE_UNKONWN;
  eAcMode mode = eACMODE_UNKONWN;
  if (0 == uni_strcmp(setting->cmd, "acPowerOn")) {
    state = AcDeviceSetState(eACSTATE_ON);
  } else if (0 == uni_strcmp(setting->cmd, "acPowerOff")) {
    state = AcDeviceSetState(eACSTATE_OFF);
  } else {
    LOGE(TAG, "unknown cmd: %s", setting->cmd);
    return -1;
  }
  LOGT(TAG, "AC power state: %d", state);
  if (eACSTATE_OFF == state) {
    uni_strncpy(g_power_off_reply, setting->reply_files, sizeof(g_power_off_reply) - 1);
    return user_asr_goto_sleep();
  } else if (eACSTATE_ON == state) {
    mode = AcDeviceGetMode();
    switch (mode) {
      case eACMODE_COOL:
        return user_player_reply_list_num(setting->reply_files, 0);
      case eACMODE_HAT:
        return user_player_reply_list_num(setting->reply_files, 1);
      case eACMODE_DRY:
        return user_player_reply_list_num(setting->reply_files, 2);
      case eACMODE_FAN:
        return user_player_reply_list_num(setting->reply_files, 3);
      case eACMODE_AUTO:
        return user_player_reply_list_num(setting->reply_files, 4);
      default:
        LOGE(TAG, "Unknown mode: %d", mode);
        break;
    }
  } else {
    LOGE(TAG, "invalid AC state: %d", state);
  }
  return -1;
}

static int _ac_off_replay(void) {
#ifdef DEFAULT_PCM_WAKEUP
  return user_player_reply_list_num(DEFAULT_PCM_WAKEUP, 0);
#else
  return user_player_reply_list_random(HI_AC_OFF);
#endif
}

static int _ac_temp_change_replay(char *reply_files, eAcTemp temp) {
  eAcMode mode = AcDeviceGetMode();
  int diff = temp - eACTEMP_16;
  if (temp <= eACTEMP_20) {
    if (eACMODE_COOL == mode) {
      return user_player_reply_list_num(reply_files, diff * 2 + 1);
    }
    return user_player_reply_list_num(reply_files, diff * 2);
  }
  return user_player_reply_list_num(reply_files, diff + 5);
}

static int _ac_temp_replay(event_custom_setting_t *setting) {
  eAcSate state = AcDeviceGetState();
  eAcTemp temp = eACTEMP_UNKONWN;
  eAcMode mode = eACMODE_UNKONWN;
  if (eACSTATE_ON != state) {
    return _ac_off_replay();
  }
  if (0 == uni_strcmp(setting->cmd, "acTemp16")) {
    temp = AcDeviceSetTemp(eACTEMP_16);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp17")) {
    temp = AcDeviceSetTemp(eACTEMP_17);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp18")) {
    temp = AcDeviceSetTemp(eACTEMP_18);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp19")) {
    temp = AcDeviceSetTemp(eACTEMP_19);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp20")) {
    temp = AcDeviceSetTemp(eACTEMP_20);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp21")) {
    temp = AcDeviceSetTemp(eACTEMP_21);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp22")) {
    temp = AcDeviceSetTemp(eACTEMP_22);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp23")) {
    temp = AcDeviceSetTemp(eACTEMP_23);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp24")) {
    temp = AcDeviceSetTemp(eACTEMP_24);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp25")) {
    temp = AcDeviceSetTemp(eACTEMP_25);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp26")) {
    temp = AcDeviceSetTemp(eACTEMP_26);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp27")) {
    temp = AcDeviceSetTemp(eACTEMP_27);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp28")) {
    temp = AcDeviceSetTemp(eACTEMP_28);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp29")) {
    temp = AcDeviceSetTemp(eACTEMP_29);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp30")) {
    temp = AcDeviceSetTemp(eACTEMP_30);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp31")) {
    temp = AcDeviceSetTemp(eACTEMP_31);
  } else if (0 == uni_strcmp(setting->cmd, "acTemp32")) {
    temp = AcDeviceSetTemp(eACTEMP_32);
  } else if (0 == uni_strcmp(setting->cmd, "acTempInc")) {
    temp = AcDeviceTempInc();
    return _ac_temp_change_replay(setting->reply_files, temp);
  } else if (0 == uni_strcmp(setting->cmd, "acTempDec")) {
    temp = AcDeviceTempDec();
    return _ac_temp_change_replay(setting->reply_files, temp);
  } else if (0 == uni_strcmp(setting->cmd, "acTempIncBig")) {
    temp = AcDeviceTempIncBig();
    return _ac_temp_change_replay(setting->reply_files, temp);
  } else if (0 == uni_strcmp(setting->cmd, "acTempDecBig")) {
    temp = AcDeviceTempDecBig();
    return _ac_temp_change_replay(setting->reply_files, temp);
  } else {
    LOGE(TAG, "unknown cmd: %s", setting->cmd);
    return -1;
  }
  LOGT(TAG, "AC temp state: %d", temp);
  if (temp <= eACTEMP_20) {
    mode = AcDeviceGetMode();
    if (eACMODE_COOL == mode) {
      return user_player_reply_list_num(setting->reply_files, 1);
    }
    return user_player_reply_list_num(setting->reply_files, 0);
  }
  return user_player_reply_list_random(setting->reply_files);
}

static int _ac_wind_replay(event_custom_setting_t *setting) {
  eAcSate state = AcDeviceGetState();
  eAcWindSpeed speed = eACWINDSPEED_UNKONWN;
  eAcMode mode = AcDeviceGetMode();
  if (eACSTATE_ON != state) {
    return _ac_off_replay();
  }
  if (0 == uni_strcmp(setting->cmd, "acWindHigh")) {
    if (eACMODE_DRY == mode) {
      return user_player_reply_list_num(setting->reply_files, 1);
    }
    speed = AcDeviceSetWindSpeed(eACWINDSPEED_HIGH);
    return user_player_reply_list_num(setting->reply_files, 0);
  } else if (0 == uni_strcmp(setting->cmd, "acWindMid")) {
    if (eACMODE_DRY == mode) {
      return user_player_reply_list_num(setting->reply_files, 1);
    }
    speed = AcDeviceSetWindSpeed(eACWINDSPEED_MID);
    return user_player_reply_list_num(setting->reply_files, 0);
  } else if (0 == uni_strcmp(setting->cmd, "acWindLow")) {
    if (eACMODE_DRY == mode) {
      return user_player_reply_list_num(setting->reply_files, 1);
    }
    speed = AcDeviceSetWindSpeed(eACWINDSPEED_LOW);
    return user_player_reply_list_num(setting->reply_files, 0);
  } else if (0 == uni_strcmp(setting->cmd, "acWindMax")) {
    speed = AcDeviceSetWindSpeed(eACWINDSPEED_HIGH);
  } else if (0 == uni_strcmp(setting->cmd, "acWindMin")) {
    speed = AcDeviceSetWindSpeed(eACWINDSPEED_LOW);
  } else if (0 == uni_strcmp(setting->cmd, "acWindMute")) {
    speed = AcDeviceSetWindSpeed(eACWINDSPEED_LOW);
  } else if (0 == uni_strcmp(setting->cmd, "acWindAuto")) {
    speed = AcDeviceSetWindSpeed(eACWINDSPEED_MID);
  } else if (0 == uni_strcmp(setting->cmd, "acWindInc")) {
    speed = AcDeviceGetWindSpeed();
    if (eACWINDSPEED_HIGH == speed) {
      return user_player_reply_list_num(setting->reply_files, 1);
    }
    speed = AcDeviceWindSpeedInc();
    return user_player_reply_list_num(setting->reply_files, 0);
  } else if (0 == uni_strcmp(setting->cmd, "acWindDec")) {
    speed = AcDeviceGetWindSpeed();
    if (eACWINDSPEED_LOW == speed) {
      return user_player_reply_list_num(setting->reply_files, 1);
    }
    speed = AcDeviceWindSpeedDec();
    return user_player_reply_list_num(setting->reply_files, 0);
  } else {
    LOGE(TAG, "unknown cmd: %s", setting->cmd);
    return -1;
  }
  LOGT(TAG, "AC speed state: %d", speed);
  return user_player_reply_list_random(setting->reply_files);
}

static int _ac_mode_replay(event_custom_setting_t *setting) {
  eAcSate state = AcDeviceGetState();
  eAcMode mode = eACMODE_UNKONWN;
  if (eACSTATE_ON != state) {
    return _ac_off_replay();
  }
  if (0 == uni_strcmp(setting->cmd, "acModeCool")) {
    mode = AcDeviceSetMode(eACMODE_COOL);
  } else if (0 == uni_strcmp(setting->cmd, "acModeDry")) {
    mode = AcDeviceSetMode(eACMODE_DRY);
  } else if (0 == uni_strcmp(setting->cmd, "acModeFan")) {
    mode = AcDeviceSetMode(eACMODE_FAN);
  } else if (0 == uni_strcmp(setting->cmd, "acModeHat")) {
    mode = AcDeviceSetMode(eACMODE_HAT);
  } else {
    LOGE(TAG, "unknown cmd: %s", setting->cmd);
    return -1;
  }
  LOGT(TAG, "AC mode state: %d", mode);
  return user_player_reply_list_random(setting->reply_files);
}

static int _ac_swing_replay(event_custom_setting_t *setting) {
  eAcSate state = AcDeviceGetState();
  eAcSwing swing = AcDeviceGetSwingState();
  if (eACSTATE_ON != state) {
    return _ac_off_replay();
  }
  if (0 == uni_strcmp(setting->cmd, "acSwingCrossOn")) {
    swing = AcDeviceSetSwingState(eACSWING_CROSS_ON);
  } else if (0 == uni_strcmp(setting->cmd, "acSwingCrossOff")) {
    swing = AcDeviceSetSwingState(eACSWING_CROSS_OFF);
  } else if (0 == uni_strcmp(setting->cmd, "acSwingVertOn")) {
    swing = AcDeviceSetSwingState(eACSWING_VERT_ON);
  } else if (0 == uni_strcmp(setting->cmd, "acSwingVertOff")) {
    swing = AcDeviceSetSwingState(eACSWING_VERT_OFF);
  } else if (0 == uni_strcmp(setting->cmd, "acSwingOn")) {
    swing = AcDeviceSetSwingState(eACSWING_ALL_ON);
  } else if (0 == uni_strcmp(setting->cmd, "acSwingOff")) {
    swing = AcDeviceSetSwingState(eACSWING_ALL_OFF);
  } else {
    LOGE(TAG, "unknown cmd: %s", setting->cmd);
    return -1;
  }
  LOGT(TAG, "AC swing state: %d", swing);
  return user_player_reply_list_random(setting->reply_files);
}

static int _ac_sleep_replay(event_custom_setting_t *setting) {
  eAcSate state = AcDeviceGetState();
  uni_bool is_on = AcDeviceGetSkillState(eACSKILL_SLEEP);
  eAcMode mode = AcDeviceGetMode();
  if (eACSTATE_ON != state) {
    return _ac_off_replay();
  }
  if (0 == uni_strcmp(setting->cmd, "acSleepOn")) {
    is_on = AcDeviceSetSkillState(eACSKILL_SLEEP, true);
    if (eACMODE_COOL == mode) {
      return user_player_reply_list_num(setting->reply_files, 1);
    }
    return user_player_reply_list_num(setting->reply_files, 0);
  } else if (0 == uni_strcmp(setting->cmd, "acSleepOff")) {
    is_on = AcDeviceSetSkillState(eACSKILL_SLEEP, false);
  } else {
    LOGE(TAG, "unknown cmd: %s", setting->cmd);
    return -1;
  }
  LOGT(TAG, "AC sleep state: %d", is_on);
  return user_player_reply_list_random(setting->reply_files);
}

static int _ac_humidifier_replay(event_custom_setting_t *setting) {
  eAcSate state = AcDeviceGetState();
  uni_bool is_on = AcDeviceGetSkillState(eACSKILL_HUMID);
  if (eACSTATE_ON != state) {
    return _ac_off_replay();
  }
  if (0 == uni_strcmp(setting->cmd, "acHumidifierOn")) {
    is_on = AcDeviceSetSkillState(eACSKILL_HUMID, true);
  } else if (0 == uni_strcmp(setting->cmd, "acHumidifierOff")) {
    is_on = AcDeviceSetSkillState(eACSKILL_HUMID, false);
  } else {
    LOGE(TAG, "unknown cmd: %s", setting->cmd);
    return -1;
  }
  LOGT(TAG, "AC humidifier state: %d", is_on);
  return user_player_reply_list_random(setting->reply_files);
}

static int _ac_screen_replay(event_custom_setting_t *setting) {
  eAcSate state = AcDeviceGetState();
  uni_bool is_on = AcDeviceGetSkillState(eACSKILL_SCREEN);
  if (eACSTATE_ON != state) {
    return _ac_off_replay();
  }
  if (0 == uni_strcmp(setting->cmd, "acScreenOn")) {
    is_on = AcDeviceSetSkillState(eACSKILL_SCREEN, true);
  } else if (0 == uni_strcmp(setting->cmd, "acScreenOff")) {
    is_on = AcDeviceSetSkillState(eACSKILL_SCREEN, false);
  } else {
    LOGE(TAG, "unknown cmd: %s", setting->cmd);
    return -1;
  }
  LOGT(TAG, "AC screen state: %d", is_on);
  return user_player_reply_list_random(setting->reply_files);
}

static int _ac_energy_replay(event_custom_setting_t *setting) {
  eAcSate state = AcDeviceGetState();
  uni_bool is_on = AcDeviceGetSkillState(eACSKILL_ENERGY);
  if (eACSTATE_ON != state) {
    return _ac_off_replay();
  }
  if (0 == uni_strcmp(setting->cmd, "acEnergyOn")) {
    is_on = AcDeviceSetSkillState(eACSKILL_ENERGY, true);
  } else if (0 == uni_strcmp(setting->cmd, "acEnergyOff")) {
    is_on = AcDeviceSetSkillState(eACSKILL_ENERGY, false);
  } else {
    LOGE(TAG, "unknown cmd: %s", setting->cmd);
    return -1;
  }
  LOGT(TAG, "AC screen state: %d", is_on);
  return user_player_reply_list_random(setting->reply_files);
}

static void _custom_setting_cb(USER_EVENT_TYPE event,
                                     user_event_context_t *context) {
  event_custom_setting_t *setting = NULL;
  if (context) {
    setting = &context->custom_setting;
    if (0 == uni_strncmp(setting->cmd, "acPower", uni_strlen("acPower"))) {
      _ac_power_replay(setting);
    } else if (0 == uni_strncmp(setting->cmd, "acTemp", uni_strlen("acTemp"))) {
      _ac_temp_replay(setting);
    } else if (0 == uni_strncmp(setting->cmd, "acMode", uni_strlen("acMode"))) {
      _ac_mode_replay(setting);
    } else if (0 == uni_strncmp(setting->cmd, "acWind", uni_strlen("acWind"))) {
      _ac_wind_replay(setting);
    } else if (0 == uni_strncmp(setting->cmd, "acSwing", uni_strlen("acSwing"))) {
      _ac_swing_replay(setting);
    } else if (0 == uni_strncmp(setting->cmd, "acSleep", uni_strlen("acSleep"))) {
      _ac_sleep_replay(setting);
    } else if (0 == uni_strncmp(setting->cmd, "acHumidifier", uni_strlen("acHumidifier"))) {
      _ac_humidifier_replay(setting);
    } else if (0 == uni_strncmp(setting->cmd, "acScreen", uni_strlen("acScreen"))) {
      _ac_screen_replay(setting);
    } else if (0 == uni_strncmp(setting->cmd, "acEnergy", uni_strlen("acEnergy"))) {
      _ac_energy_replay(setting);
    } else {
      /* don't reply if other setting command */
    }
  }
}

static void _goto_awakend_cb(USER_EVENT_TYPE event,
                                     user_event_context_t *context) {
  event_goto_awakend_t *awakend = NULL;
  if (context) {
    awakend = &context->goto_awakend;
    if (EVENT_TRIGGER_ASR == awakend->trigger) {
      LOGT(TAG, "ASR command: %s -> %s -> %s", awakend->cmd, awakend->word_str, awakend->reply_files);
    } else {
      LOGT(TAG, "External command: %s", awakend->reply_files);
    }
    if (awakend->reply_files) {
      if(eACSTATE_ON == AcDeviceGetState()) {
        user_player_reply_list_num(awakend->reply_files, 1);
      } else {
        user_player_reply_list_num(awakend->reply_files, 0);
      }
    }
  }
}

static void _goto_sleeping_cb (USER_EVENT_TYPE event,
                                     user_event_context_t *context) {
  event_goto_sleeping_t *sleeping = NULL;
  if (context) {
    sleeping = &context->goto_sleeping;
    if (EVENT_TRIGGER_ASR == sleeping->trigger) {
      LOGT(TAG, "ASR command: %s -> %s -> %s", sleeping->cmd, sleeping->word_str,
                                               sleeping->reply_files);
    } else {
      LOGT(TAG, "External command: %s", sleeping->reply_files);
    }
    if (sleeping->reply_files) {
      if(EVENT_TRIGGER_USER == sleeping->trigger) {
        user_player_reply_list_random(g_power_off_reply);
      } else {
        user_player_reply_list_random(sleeping->reply_files);
      }
    }
  }
}

static void _volume_setting_cb(USER_EVENT_TYPE event,
                                     user_event_context_t *context) {
 event_volume_setting_t *setting = NULL;
 if (context) {
   setting = &context->voluem_setting;
   LOGT(TAG, "user command: %s", setting->cmd);
   if (0 == uni_strcmp(setting->cmd, "volumeUpUni")) {
    if (setting->value >= setting->max_val) {
      user_player_reply_list_num(setting->reply_files, 1);
    } else {
      user_player_set_volume_up();
      user_player_reply_list_num(setting->reply_files, 0);
    }
   } else if (0 == uni_strcmp(setting->cmd, "volumeDownUni")) {
    if (setting->value <= setting->min_val) {
      user_player_reply_list_num(setting->reply_files, 1);
    } else {
      user_player_set_volume_down();
      user_player_reply_list_num(setting->reply_files, 0);
    }
   } else {
     LOGE(TAG, "Unknown cmd: %s", setting->cmd);
   }
 }
}

static void _register_event_callback(void) {
  user_event_subscribe_event(USER_CUSTOM_SETTING, _custom_setting_cb);
  user_event_subscribe_event(USER_GOTO_AWAKENED, _goto_awakend_cb);
  user_event_subscribe_event(USER_GOTO_SLEEPING, _goto_sleeping_cb);
  user_event_subscribe_event(USER_VOLUME_SETTING, _volume_setting_cb);
}

int hb_smart_ac(void) {
  AcDeviceInit();
  _register_event_callback();
  return 0;
}

